#ifndef _LOAD_COM_HPP_
#define _LOAD_COM_HPP_

#include <dlcom/unknown.h>
#include <utilex/calldll.hpp>

class CComLoader : protected IImpModuleBase
{
public:
	DefineDllGetClassObject 	DllGetClassObject;
	DefineDllGetAt				DllGetAt;
	DefineDllGetCount			DllGetCount;
	DefineDllProgIDFromCLSID	DllProgIDFromCLSID;
	DefineDllCanUnloadNow 		DllCanUnloadNow;
	DefineDllRegisterServer 	DllRegisterServer;
	DefineDllUnregisterServer 	DllUnregisterServer;
	DefineDllStartServer		DllStartServer;
	DefineDllStopServer			DllStopServer;

public: 
	inline CComLoader()
	{
		
	} 
	virtual STFunDesc *GetFunDefs() 
	{ 
		static STFunDesc s_FunDefs[]= 
		{
			{ (char *)DllGetClassObjectFuncName,0},
			{ (char *)DllGetAtFuncName,1},
			{ (char *)DllGetCountFuncName,2},
			{ (char *)DllProgIDFromCLSIDFuncName,3},
			{ (char *)DllCanUnloadNowFuncName,4},
			{ (char *)DllRegisterServerFuncName,5},
			{ (char *)DllUnregisterServerFuncName,6},
			{ (char *)DllStartServerFuncName,7},
			{ (char *)DllStopServerFuncName,8},
			{ (char *)NULLFuncName,9}
		}; 
		return s_FunDefs;
	}
	virtual bool SetFuncAddress(size_t i,void *p)
	{
		switch(i)
		{
			case 0:
				this->DllGetClassObject = (DefineDllGetClassObject)(p);
				break;
			case 1:
				this->DllGetAt =  (DefineDllGetAt)(p);
				break;
			case 2:
				this->DllGetCount = (DefineDllGetCount)(p);
				break;
			case 3:
				this->DllProgIDFromCLSID = (DefineDllProgIDFromCLSID)(p);
				break;
			case 4:
				this->DllCanUnloadNow =  (DefineDllCanUnloadNow)(p);
				break;
			case 5:
				this->DllRegisterServer = (DefineDllRegisterServer)(p);
				break;
			case 6:
				this->DllUnregisterServer = (DefineDllUnregisterServer)(p);
				break;
			case 7:
				this->DllStartServer = (DefineDllStartServer)(p);
				break;
			case 8:
				this->DllStopServer = (DefineDllStopServer)(p);
				break;
			default:
				break;
		}
		return true;

	}
	virtual ~CComLoader()
	{
		UnloadCom();
	}
public:
	HRESULT LoadCom(LPSTRING pModPathName)
	{
		tmemset(m_szModuleName,0,MAX_PATH);
		tstring_strcpy(m_szModuleName, MAX_PATH, pModPathName);

		int nRet = Load();
		if (nRet == -1)
		{
			debug_view("CComLoader->Load fuc fail")
			wdebug_view(m_szModuleName);
			tmemset(m_szModuleName,0,MAX_PATH);
			return E_FAIL;
		}
		

		if (DllGetClassObject == NULL) {
			debug_view("CComLoader->DllGetClassObject error")
			return E_FAIL;
		}

		return S_OK;
	}
	virtual void UnloadCom()
	{
		UnLoad();
	}
	HRESULT CreateInstance(REFCLSID rclsid, IBase *prot, IBase *punkOuter, const IID& riid, void **ppv)
	{
		rc_assert(IsLoaded(),E_FAIL)
	
		_lComPtr<IComClassFactory> pClassFactory;
		pClassFactory.dispose();

		if(S_SUCCEEDED(DllGetClassObject(rclsid, IID_IComClassFactory, (void**)&pClassFactory)) && pClassFactory)
		{
			_lComPtr<IComObjectFrameworkClassFactory> pOFClassFactory;
			pOFClassFactory.dispose();
			pClassFactory->QueryInterface(IID_IComObjectFrameworkClassFactory, (void**)&pOFClassFactory);
			if (pOFClassFactory) {
				return pOFClassFactory->CreateInstance(prot, punkOuter, riid, ppv);
			}	

		}
		return E_FAIL;
	}
	LONG GetCount()
	{
		return this->DllGetCount();
	}
	CLSID GetAt(LONG nIndex)
	{
		return this->DllGetAt(nIndex);
	}
	LPCSTR ProgIDFromCLSID(REFCLSID clsid)
	{
		return this->DllProgIDFromCLSID(clsid);
	}
	int IsLoaded()
	{
		return IImpModuleBase::IsLoaded();
	}
protected:
	_lComPtr<IComObjectFrameworkClassFactory> m_pClassFactory;

};

#endif 
